package com.bix.util.blizfiles.mpq;

/**
 * This class and its implementation was derived directly from the FAQ at:
 * 	http://home.devklog.net/trac/mpqkit/wiki/MoPaQ_Format
 * 
 * ALL code in my implementation of this FAQ are based on that FAQ and the
 * source code from libmpq.
 * 
 * @author squid
 */
public class MPQCrypt {
	private static int[] cryptTable = new int[0x500];

	/**
	 * Static method that initialized s
	 */
	static {
		long seed = 0x00100001;
		
		for (int index1 = 0; index1 < 0x100; index1++) {
			for (int i = 0, index2 = index1; i < 5; i++, index2 += 0x100) {
				seed = (seed * 125 + 3) % 0x2AAAABL;
				long temp1 = (seed & 0xFFFFL) << 0x10;

				seed = (seed * 125 + 3) % 0x2AAAABL;
				long temp2 = (seed & 0xFFFFL);

				cryptTable[index2] = (int)(temp1 | temp2);
			}
		}
		
		for (int i = 0; i < cryptTable.length; i++) {
			System.out.print ("0x" + Integer.toHexString(cryptTable[i]) + ", ");
		}
	}

	public static int[] DecryptData(int[] buffer, int key) {
		int results[] = new int[buffer.length];
		int length = buffer.length;
		int index = 0;

		long ch;
		long seed = 0xEEEEEEEE;
		while (length-- > 0) {
			seed += cryptTable[(0x400 + (key & 0xFF))];
			ch = buffer[(int) (key + seed)];
			key = ((~key << 0x15) + 0x11111111) | (key >> 0x0B);
			seed = ch + seed + (seed << 5) + 3;
			results[index++] = (int)ch;
		}

		return results;
	}
	
	private	int	MPQ_HASH_TABLE_OFFSET	= 0;
	private	int	MPQ_HASH_NAME_A				= 1;
	private	int	MPQ_HASH_NAME_B				= 2;
	private	int	MPQ_HASH_FILE_KEY			= 3;

	// Based on code from StormLib.
	public static int HashString(String str, int hashType) {
		long seed1 = 0x7FED7FED;
		long seed2 = 0xEEEEEEEE;
		String upper = str.toUpperCase();

		for (byte b : upper.getBytes()) {
			seed1 = cryptTable[(hashType ^ 0x100) + b] ^ (seed1 + seed2);
			seed2 = b + seed1 + seed2 + (seed2 << 5) + 3;
		}
		return (int) (seed1 & 0xFFFFFFFF);
	}
}
